﻿Option Strict On
Option Infer On
Option Explicit On

Imports System
Imports System.Linq
Imports System.Xml.Linq
Imports System.Collections.Generic
Imports GenDotNet.StoredProcModel
Imports GenDotNet.Task.Common
Imports <xmlns:orm="http://kadgen.com/KADORM.xsd">
Imports <xmlns:kd="http://kadgen.com/Special.xsd">

Public Class RecordsetData
   Inherits BaseData
   Implements IRecordsetData

   Private mColumns As IEnumerable(Of IColumnData)
   Private mJoins As IEnumerable(Of IJoinData)
   Private mOrderBies As IEnumerable(Of IOrderByData)
   Private mMainTableName As String
   Private mMainTableSchema As String

   Public Shared Function Load( _
            ByVal rootdata As RootData, _
            ByVal element As XElement) _
            As IRecordsetData
      Return New RecordsetData(rootdata, element)
   End Function

   Private Sub New( _
           ByVal rootdata As RootData, _
           ByVal element As XElement)
      MyBase.New(rootdata, element)
      If element.Name.LocalName = "SetSelect" Then
         Me.mColumns = ColumnData.Load(rootdata, From e In element.<orm:SetSelectColumn>)
         Me.mJoins = JoinData.Load(rootdata, From e In element...<orm:Join>)
         Me.mOrderBies = New List(Of IOrderByData)
         If mColumns.Count > 0 Then
            ' This is because the SetSelect.TableName is the TableName, not the OriginalName and we cannot 
            ' count on the main one being loaded first.
            Me.mMainTableName = element.<orm:SetSelectColumn>.@TableName
         End If
         Me.mMainTableSchema = element.@Schema
      Else
         Me.mColumns = ColumnData.Load(rootdata, From e In element...<orm:TableColumn>)
         Me.mJoins = JoinData.Load(rootdata, From e In element...<orm:Join>)
         Me.mOrderBies = OrderByData.Load(rootdata, Me, From e In element...<orm:OrderBy>)
         Me.mMainTableName = (From e In element...<orm:BuildTable>).FirstOrDefault.@OriginalName
         Me.mMainTableSchema = (From e In element...<orm:BuildTable>).FirstOrDefault.@Schema
      End If
      If rootdata.GetTable(mMainTableSchema, mMainTableName) Is Nothing Then
         rootdata.AddNewTable(New TableData(rootdata, mMainTableSchema, mMainTableName))
      End If
   End Sub

   Public ReadOnly Property ChildFlag() _
             As Int32 _
             Implements IRecordsetData.ChildFlag
      Get
         Return CInt(Me.Element.@ChildFlag)
      End Get
   End Property

   Public ReadOnly Property Columns() _
            As IEnumerable(Of IColumnData) _
            Implements IRecordsetData.Columns
      Get
         Return mColumns
      End Get
   End Property

   Public ReadOnly Property InsertPriority() _
            As Int32 _
            Implements IRecordsetData.InsertPriority
      Get
         Return CInt(Me.Element.@InsertPriority)
      End Get
   End Property

   Public ReadOnly Property Joins() _
            As IEnumerable(Of IJoinData) _
            Implements IRecordsetData.Joins
      Get
         Return mJoins
      End Get
   End Property

   Public ReadOnly Property Name() _
            As String _
            Implements IRecordsetData.Name
      Get
         Return Me.Element.@Name
      End Get
   End Property

   Public ReadOnly Property OrderBies() _
            As IEnumerable(Of IOrderByData) _
            Implements IRecordsetData.OrderBies
      Get
         Return mOrderBies
      End Get
   End Property

   Public ReadOnly Property Distinct() As Boolean Implements IRecordsetData.IsDistinct
      Get
         Return Element.@kd:Distinct.IsTrue
      End Get
   End Property

   Public ReadOnly Property MainTable() _
            As StoredProcModel.ITableData _
            Implements StoredProcModel.IRecordsetData.MainTable
      Get
         Return RootData.GetTable(mMainTableSchema, mMainTableName)
      End Get
   End Property

   Public Function GetColumn(ByVal columnName As String) As IColumnData Implements IRecordsetData.GetColumn
      Return (From column In Me.mColumns Where column.Name = columnName).FirstOrDefault
   End Function

   Public ReadOnly Property PrimaryKeyColumns() _
            As IEnumerable(Of IColumnData) _
            Implements IRecordsetData.PrimaryKeyColumns
      Get
         Return From column In Columns Where column.IsPrimaryKey
      End Get
   End Property

   Private ReadOnly Property FirstColumns() As IEnumerable(Of IColumnData)
      Get
         ' sometimes in self joins there are multiple columns and for updates, you only want the first.
         Return From column In Columns Group By column.Name Into Group Select Group.First
      End Get
   End Property

   Public ReadOnly Property InsertColumns() _
            As IEnumerable(Of StoredProcModel.IColumnData) _
            Implements IRecordsetData.InsertColumns
      Get
         Return From column In FirstColumns Where Not column.IsReadOnly And column.Table Is Me.MainTable
      End Get
   End Property

   Public ReadOnly Property UpdateColumns() _
            As IEnumerable(Of StoredProcModel.IColumnData) _
            Implements IRecordsetData.UpdateColumns
      Get
         Return From column In FirstColumns Where Not column.IsReadOnly And Not column.IsPrimaryKey And column.Table Is Me.MainTable
      End Get
   End Property
End Class
